package com.example.yx1.demo35;

import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.boot.*;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext;
import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext;
import org.springframework.boot.web.servlet.server.ServletWebServerFactory;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.*;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.io.ClassPathResource;

public class A35_2 {
    public static void main(String[] args) throws Exception {
        SpringApplication app = new SpringApplication();
        app.addInitializers(applicationContext -> System.out.println("执行初始化器增强..."));


        System.out.println(">>>>>>>>>>>>>>>>>2.封装启动args");
        DefaultApplicationArguments arguments = new DefaultApplicationArguments(args);


        System.out.println(">>>>>>>>>>>>>>>>>8.创建容器");
        GenericApplicationContext context = createApplicationContext(WebApplicationType.SERVLET);

        System.out.println(">>>>>>>>>>>>>>>>>9.准备容器");//在此处因为有了容器，可以回调之前添加的初始化器
        for (ApplicationContextInitializer initializer : app.getInitializers()) {
            initializer.initialize(context);
        }

        System.out.println(">>>>>>>>>>>>>>>>>10.加载bean定义");//被注解标注的bean或者xml的bean
        DefaultListableBeanFactory factory = context.getDefaultListableBeanFactory();
        AnnotatedBeanDefinitionReader reader = new AnnotatedBeanDefinitionReader(factory);
        reader.register(Config.class);//解析Config类所有的bean定义

        //xml路径扫描
        XmlBeanDefinitionReader reader1 = new XmlBeanDefinitionReader(factory);
        reader1.loadBeanDefinitions(new ClassPathResource("b03.xml"));
        //组件扫描
        ClassPathBeanDefinitionScanner reader2 = new ClassPathBeanDefinitionScanner(factory);




        System.out.println(">>>>>>>>>>>>>>>>>11.refresh 容器");
        context.refresh();

        for (String name : context.getBeanDefinitionNames()) {
            System.out.println("名字: " + name + " 来源: " + context.getBeanFactory().getBeanDefinition(name));
        }


        System.out.println(">>>>>>>>>>>>>>>>>12.执行 runner");//其实就是一种实现了特定接口的 bean,在这里可以实现一些数据的预加载什么的
        for (CommandLineRunner runner : context.getBeansOfType(CommandLineRunner.class).values()) {
            runner.run(args);
        }

        for (ApplicationRunner runner : context.getBeansOfType(ApplicationRunner.class).values()) {
            runner.run(arguments);
        }

    }

    private static GenericApplicationContext createApplicationContext (WebApplicationType type) {
        GenericApplicationContext context = null;
        switch (type){
            case SERVLET : context = new AnnotationConfigServletWebServerApplicationContext();break;
            case REACTIVE:  context = new AnnotationConfigReactiveWebServerApplicationContext();break;
            case NONE: context = new AnnotationConfigApplicationContext();
        }
        return context;
    }

    static class Bean4{}

    static class Bean5{}

    static class Bean6{}

    @Configuration
    static class Config {
        @Bean
        public Bean5 bean5() {
            return new Bean5();
        }
        @Bean
        public ServletWebServerFactory servletWebServerFactory() {return new TomcatServletWebServerFactory();
        }

        @Bean
        public ApplicationRunner applicationRunner() {return new ApplicationRunner() {
            @Override
            public void run(ApplicationArguments args) throws Exception {
                System.out.println("ApplicationRunner.......");
            }
        };}
        @Bean
        public CommandLineRunner commandLineRunner () {return new CommandLineRunner() {
            @Override
            public void run(String... args) throws Exception {
                System.out.println("CommandLineRunner....");
            }
        };}
    }
}
